home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / games / IndiZone / vroom / server.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  48.3 KB  |  2,245 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <stdarg.h>
  20. #include <unistd.h>
  21. #include <fcntl.h>
  22. #include <sys/types.h>
  23. #include <sys/socket.h>
  24. #include <sys/time.h>
  25. #include <netinet/in.h>
  26. #include <arpa/inet.h>
  27. #include <netdb.h>
  28. #include <errno.h>
  29. #include <malloc.h>
  30. #include <bstring.h>
  31.  
  32. #include <X11/Intrinsic.h>
  33. #include <Xm/Xm.h>
  34. #include <Xm/List.h>
  35. #include <GL/GLwDrawA.h>
  36.  
  37. #include "vroom.h"
  38. #include "server.h"
  39. #include "client.h"
  40. #include "track.h"
  41. #include "ogl.h"
  42. #include "solo.h"
  43. #include "multicast.h"
  44. #include "playmode.h"
  45. #include "sound.h"
  46. #include "messages.h"
  47.  
  48. #define    UPDATE_SPACING        (1.0f)    /* Time between status broadcasts */
  49. #define    COURSE_ACK_DEADLINE    (10.0f)    /* Time for clients to ack course */
  50. #define    TRIAL_SKILL_LEVEL    (0.85f)
  51.  
  52.  
  53. typedef void    (*ServerFunc)( void ) ;
  54.  
  55. typedef struct _clientNode {
  56.     long            id ;
  57.     long            status ;
  58.     long            position ;
  59.     float            time ;
  60.     float            nextDeadLine ;
  61.     struct _clientNode    *next ;
  62.     } ClientNode ;
  63.  
  64. /* BEGIN PROTOTYPES -S server.c */
  65. static void             addClient( long id ) ;
  66. static void             addPlayer( long id ) ;
  67. static void             addToClientListEnd( ClientNode *newClient ) ;
  68. static void             autoFinish( void ) ;
  69. static void             broadcastAckPacket( long id, long status, long data ) ;
  70. static void             broadcastCoursePacket( outCoursePacket *packet ) ;
  71. static void             broadcastNamePacket( long nPlayer ) ;
  72. static void             broadcastRacePacket( void ) ;
  73. static void             broadcastStatusPacket( void ) ;
  74. static int              computeDistances( int laps ) ;
  75. static int              createReadSocket( int port,
  76.                             struct sockaddr_in *addr ) ;
  77. static void             fillCourseSelectorList( Widget courseSelector ) ;
  78. static ClientNode *     findClient( long id ) ;
  79. static int              findPlayer( long id ) ;
  80. static int              initInputSpigot( int port ) ;
  81. static int              loadTimes( int laps ) ;
  82. static int              processInfoPacket( inInfoPacket *packet, int size ) ;
  83. static int              processMsgPacket( inMsgPacket *packet, int size ) ;
  84. static int              processNamePacket( inNamePacket *packet, int size ) ;
  85. static int              processSpeedPacket( inSpeedPacket *packet, int size ) ;
  86. static void             readCourses( void ) ;
  87. static void             readInputSocket( void ) ;
  88. static void             removeClient( long id ) ;
  89. static void             removePlayer( long id ) ;
  90. static void             resetClientDeadline( long id ) ;
  91. static void             sendToNetwork( void *buf, int size ) ;
  92. static void             serverNoOp( void ) ;
  93. static void             serverPostRace( void ) ;
  94. static void             serverPostTrial( void ) ;
  95. static void             serverPreRace( void ) ;
  96. static void             serverPreTrial( void ) ;
  97. static void             serverRace( void ) ;
  98. static void             serverTrial( void ) ;
  99. static void             serverWaitForCourseAck( void ) ;
  100. static void             serverWaitForCourseSel( void ) ;
  101. static void             startTeamTrials( int courseNumber ) ;
  102. static void             tallyCourseVotes( void ) ;
  103. static void             updateClientList( void ) ;
  104. static void             updateNames( void ) ;
  105. /* END PROTOTYPES -S server.c */
  106.  
  107. Widget                serverCourseLabel = NULL ;
  108.  
  109. extern char            *basename ;
  110. extern char            teamPosition[] ;
  111. extern char            *robotName[] ;
  112. extern char            *myName ;
  113. extern int            self ;
  114. extern int            nCars ;
  115. extern int            nTracks ;
  116. extern int            nPlayers ;
  117. extern int            raceLaps ;
  118. extern int            isRobot[MAX_PLAYERS] ;
  119. extern int            carsFinished ;
  120. extern int            debugOn ;
  121. extern int            startLastLap ;
  122. extern long            myHostId ;
  123. extern float            currentTime ;
  124. extern float            startSoundTime ;
  125. extern float            speedFactor ;
  126. extern Widget            serverCourseForm ;
  127. extern Widget            courseVoteForm ;
  128. extern Widget            serverForm ;
  129. extern Widget            mainOgl ;
  130. extern Car            cars[] ;
  131. extern PlayerStruct        player[] ;
  132. extern Sfx            alertSfx ;
  133. extern Sfx            lastlapSfx ;
  134. extern Sfx            motorSfx ;
  135. extern Sfx            startSfx ;
  136. extern Sfx            toneSfx ;
  137.  
  138. static int            showRecord ;
  139. static ServerFunc        serverFunc ;
  140. static CourseNode        *courseList = NULL ;
  141. static ClientNode        *clientList = NULL ;
  142. static int            nClients = 0 ;
  143. static CourseNode        *broadcastCourse = NULL ;
  144. static int            nCourses = 0 ;
  145. static int            *courseVotes ;
  146. static int            inSock = -1 ;
  147. static struct sockaddr_in    inAddr ;
  148. static int            inLength ;
  149. static int            outFd = -1 ;
  150. static struct sockaddr_in    outAddr ;
  151. static char            *servInputName = VROOM_SERVER_INPUT_SERVICE ;
  152. static char            *servOutputName = VROOM_CLIENT_INPUT_SERVICE ;
  153. static float            lastUpdateTime ;
  154. static float            lastRaceTime ;
  155. static float            endRaceTime ;
  156. static outStatusPacket        statusPacket ;
  157. static float            serverDeadLine ;
  158. static outCoursePacket        *raceCoursePacket ;
  159. static outRacePacket        racePacket ;
  160. static float            startTime ;
  161. static float            lastTime ;
  162.  
  163.  
  164.  
  165. /*------------------------------------------------------------------------------
  166.  * Initialize the server process.
  167.  *----------------------------------------------------------------------------*/
  168. int
  169. initLocalServer(
  170.     void
  171.     )
  172. {
  173.     int    i ;
  174.     int    port ;
  175.     Widget    courseSelector ;
  176.  
  177.     busyCursor() ;
  178.  
  179.     port = getPort( servInputName, VROOM_SERVER_INPUT_PORT ) ;
  180.  
  181.     if( initInputSpigot( port ) < 0 )
  182.     {
  183.         fatalError( "Could not open socket for input." ) ;
  184.     }
  185.  
  186.     /*
  187.      * Get port number for broadcasting to clients.
  188.      */
  189.     port = getPort( servOutputName, VROOM_CLIENT_INPUT_PORT ) ;
  190.  
  191.     if( ( outFd = openMulticastSocket( &outAddr, port, getTtl(), 1,
  192.         VROOM_GROUP, NULL, "w" ) ) < 0 )
  193.     {
  194.         fatalError( "Could not open multicast socket for output." ) ;
  195.     }
  196.  
  197.     setWorkProc( VROOM_WP_RUN_SERVER, 1 ) ;
  198.     serverFunc = serverNoOp ;
  199.  
  200.     readCourses() ;
  201.  
  202.     statusPacket.type = SERVER_P_STATUS ;
  203.     statusPacket.id = myHostId ;
  204.     statusPacket.status = SERVER_ST_COURSE_SEL ;
  205.     statusPacket.nPlayers = 0 ;
  206.     nPlayers = 0 ;
  207.  
  208.     for( i = 0 ; i < MAX_PLAYERS ; i++ )
  209.     {
  210.         statusPacket.playerId[i] = i ; ;
  211.         isRobot[i] = 1 ;
  212.         strncpy( cars[i].name, robotName[i], sizeof( cars[i].name ) ) ;
  213.     }
  214.  
  215.     nClients = 0 ;
  216.     addClient( myHostId ) ;
  217.  
  218.     /*
  219.      * Show course selection chooser.
  220.      */
  221.     courseSelector = createServerCourseSelector( serverCourseForm ) ;
  222.  
  223.     updateServerCourseLabel( nPlayers ) ;
  224.  
  225.     fillCourseSelectorList( courseSelector ) ;
  226.  
  227.     createMessageArea() ;
  228.  
  229.     setAdminForm( serverCourseForm ) ;
  230.  
  231.     setServerForNextGame() ;
  232.  
  233.     unbusyCursor() ;
  234. }
  235.  
  236.  
  237.  
  238. /*------------------------------------------------------------------------------
  239.  * Create a socket for reading.
  240.  *----------------------------------------------------------------------------*/
  241. static int
  242. initInputSpigot(
  243.     int    port
  244.     )
  245. {
  246.     /*
  247.      * Create a socket.
  248.      */
  249.     if( ( inSock = createReadSocket( port, &inAddr ) ) == -1 )
  250.     {
  251.         return( -1 ) ;
  252.     }
  253.  
  254.     /*
  255.      * Turn on non-blocking I/O on the socket.
  256.      */
  257.     if( fcntl( inSock, F_SETFL, FNDELAY ) < 0 )
  258.     {
  259.         perror( "fcntl F_SETFL, FNDELAY" ) ;
  260.         return( -1 ) ;
  261.     }
  262.  
  263.     inLength = sizeof( inAddr ) ;
  264.  
  265.     return( 0 ) ;
  266. }
  267.  
  268.  
  269.  
  270. /*------------------------------------------------------------------------------
  271.  * Read input socket, check for new players.
  272.  *----------------------------------------------------------------------------*/
  273. static void
  274. readInputSocket(
  275.     void
  276.     )
  277. {
  278.     int        cnt ;
  279.     int        st ;
  280.     inputPacket    ip ;
  281.  
  282.     while( 1 )
  283.     {
  284.         /*
  285.          * Read from the socket.
  286.          */
  287.         cnt = recvfrom( inSock, (char *)&ip, sizeof( ip ), 0,
  288.                 &inAddr, &inLength ) ;
  289.  
  290.         /*
  291.          * If no data was in the socket, cnt will be -1 and errno
  292.          * will be set to EWOULDBLOCK.  Otherwise, if data was there,
  293.          * cnt will contain the size of the data packet.
  294.          */
  295.         if( cnt < 0 )
  296.         {
  297.             if( errno != EWOULDBLOCK )
  298.             {
  299.                 fatalError( "recvfrom: %s",
  300.                         strerror( errno ) ) ;
  301.             }
  302.             else
  303.             {
  304.                 updateClientList() ;
  305.                 return ;
  306.             }
  307.         }
  308.  
  309.         st = 0 ;
  310.  
  311.         switch( ip.base.type )
  312.         {
  313.             case CLIENT_P_SPEED :
  314.                 st = processSpeedPacket( &ip.speed, cnt ) ;
  315.                 break ;
  316.  
  317.             case CLIENT_P_INFO :
  318.                 st = processInfoPacket( &ip.info, cnt ) ;
  319.                 break ;
  320.  
  321.             case CLIENT_P_NAME :
  322.                 st = processNamePacket( &ip.name, cnt ) ;
  323.                 break ;
  324.  
  325.             case CLIENT_P_MESSAGE :
  326.                 st = processMsgPacket( &ip.msg, cnt ) ;
  327.                 break ;
  328.  
  329.             default :
  330.                 fprintf( stderr, "%s: unknown packet size "
  331.                     "received (%d)\n", basename, cnt ) ;
  332.                 break ;
  333.         }
  334.  
  335.         if( st )
  336.         {
  337.             fprintf( stderr, "%s: bad client packet size received "
  338.                 "(%d bytes, type = 0x%08x)\n", basename, cnt,
  339.                 ip.base.type ) ;
  340.         }
  341.     }
  342. }
  343.  
  344.  
  345.  
  346. /*------------------------------------------------------------------------------
  347.  * Create a socket for players to connect to.
  348.  *----------------------------------------------------------------------------*/
  349. static int
  350. createReadSocket(
  351.     int            port,
  352.     struct sockaddr_in    *addr
  353.     )
  354. {
  355.     int    sock ;
  356.     int    on ;
  357.  
  358.     sock = socket( AF_INET, SOCK_DGRAM, 0 ) ;
  359.     if( sock < 0 )
  360.     {
  361.         perror("opening stream socket");
  362.         return( -1 ) ;
  363.     }
  364.  
  365.     /*
  366.      * Initialize socket data structure.
  367.      */
  368.     addr->sin_family = AF_INET ;
  369.     addr->sin_addr.s_addr = INADDR_ANY ;
  370.     addr->sin_port = htons( port ) ;
  371.  
  372.     /*
  373.      * Allow multiple binds to the socket.
  374.      */
  375.     on = 1;
  376.     if( setsockopt( sock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on) ) < 0 )
  377.     {
  378.         close( sock ) ;
  379.         perror( "setsockopt REUSEPORT" ) ;
  380.         return( -1 ) ;
  381.     }
  382.  
  383.     /*
  384.      * Bind socket data structure to this socket.
  385.      */
  386.     if( bind( sock, addr, sizeof( *addr ) ) < 0 )
  387.     {
  388.         perror( "binding stream socket" ) ;
  389.         shutdown( sock, 0 ) ;
  390.         close( sock ) ;
  391.         return( -1 ) ;
  392.     }
  393.  
  394.     return( sock ) ;
  395. }
  396.  
  397.  
  398.  
  399. /*------------------------------------------------------------------------------
  400.  * Convert hostid to a name string.
  401.  *----------------------------------------------------------------------------*/
  402. char *
  403. hostNameFromId(
  404.     long    id,
  405.     int    showIp
  406.     )
  407. {
  408.     struct in_addr    sin ;
  409.     struct hostent    *hp ;
  410.     static char    buffer[256] ;
  411.  
  412.     sin.s_addr = id ;
  413.     hp = gethostbyaddr( &sin, sizeof( sin ), AF_INET ) ;
  414.     if( hp )
  415.     {
  416.         if( showIp )
  417.         {
  418.             sprintf( buffer, "%s (%s)", hp->h_name,
  419.                 inet_ntoa( sin ) ) ;
  420.         }
  421.         else
  422.         {
  423.             sprintf( buffer, "%s", hp->h_name ) ;
  424.         }
  425.     }
  426.     else
  427.     {
  428.         sprintf( buffer, "%s", inet_ntoa( sin ) ) ;
  429.     }
  430.     return( buffer ) ;
  431. }
  432.  
  433.  
  434.  
  435. /*------------------------------------------------------------------------------
  436.  * Add a client to the list and respond.
  437.  *----------------------------------------------------------------------------*/
  438. static void
  439. addClient(
  440.     long    id
  441.     )
  442. {
  443.     ClientNode    *client ;
  444.  
  445.     /*
  446.      * First, make sure client is not already in list.
  447.      */
  448.     if( ( client = findClient( id ) ) == NULL )
  449.     {
  450.         client = (ClientNode *)malloc( sizeof( ClientNode ) ) ;
  451.         if( client == NULL )
  452.         {
  453.             broadcastAckPacket( id, ACK_ST_FAIL, 0 ) ;
  454.             return ;
  455.         }
  456.         /*
  457.          * Add client as a player (and inform of player number).
  458.          */
  459.         else if( nClients < MAX_PLAYERS &&
  460.             statusPacket.status == SERVER_ST_COURSE_SEL )
  461.         {
  462.             client->id = id ;
  463.             client->status = ACK_ST_CANDIDATE ;
  464.             client->position = nClients ;
  465.             client->time = currentTime ;
  466.             /*
  467.              * Insert player clients at first of chain.
  468.              */
  469.             client->next = clientList ;
  470.             clientList = client ;
  471.             if( id == myHostId )
  472.             {
  473.                 addPlayer( id ) ;
  474.                 strncpy( cars[self].name, myName,
  475.                     sizeof( cars[self].name ) ) ;
  476.             }
  477.             broadcastAckPacket( id, ACK_ST_CANDIDATE, nClients ) ;
  478.         }
  479.         else
  480.         {
  481.             broadcastAckPacket( id, ACK_ST_WAIT, nClients ) ;
  482.             client->id = id ;
  483.             client->status = ACK_ST_WAIT ;
  484.             client->position = nClients ;
  485.             client->time = currentTime ;
  486.             client->next = NULL ;
  487.             addToClientListEnd( client ) ;
  488.             broadcastCourse = courseList ;
  489.         }
  490.         nClients++ ;
  491.     }
  492.     else
  493.     {
  494.         broadcastAckPacket( id, client->status, client->position ) ;
  495.     }
  496.  
  497.     client->nextDeadLine = currentTime + CLIENT_TIMEOUT ;
  498. }
  499.  
  500.  
  501.  
  502. /*------------------------------------------------------------------------------
  503.  * Remove a client from the list and inform.
  504.  *----------------------------------------------------------------------------*/
  505. static void
  506. removeClient(
  507.     long    id
  508.     )
  509. {
  510.     ClientNode    *client = clientList ;
  511.     ClientNode    *prev = NULL ;
  512.  
  513.     while( client && client->id != id )
  514.     {
  515.         prev = client ;
  516.         client = client->next ;
  517.     }
  518.  
  519.     if( client != NULL && client->id == id )
  520.     {
  521.         broadcastAckPacket( id, ACK_ST_DROP, nClients ) ;
  522.  
  523.         if( prev == NULL )
  524.         {
  525.             clientList = client->next ;
  526.         }
  527.         else
  528.         {
  529.             prev->next = client->next ;
  530.         }
  531.         free( client ) ;
  532.         nClients-- ;
  533.         broadcastAckPacket( id, ACK_ST_DROP, nClients ) ;
  534.         broadcastStatusPacket() ;
  535.     }
  536. }
  537.  
  538.  
  539.  
  540. /*------------------------------------------------------------------------------
  541.  * Add a client node to the end of the chain.
  542.  *----------------------------------------------------------------------------*/
  543. static void
  544. addToClientListEnd(
  545.     ClientNode    *newClient
  546.     )
  547. {
  548.     ClientNode    *client = clientList ;
  549.  
  550.     if( client == NULL )
  551.     {
  552.         clientList = newClient ;
  553.         return ;
  554.     }
  555.  
  556.     while( client->next != NULL )
  557.     {
  558.         client = client->next ;
  559.     }
  560.  
  561.     client->next = newClient ;
  562. }
  563.  
  564.  
  565.  
  566. /*------------------------------------------------------------------------------
  567.  * Broadcast an acknowledgement packet.
  568.  *----------------------------------------------------------------------------*/
  569. static void
  570. broadcastAckPacket(
  571.     long    id,
  572.     long    status,
  573.     long    data
  574.     )
  575. {
  576.     outAckPacket    ack ;
  577.  
  578.     ack.type = SERVER_P_ACK ;
  579.     ack.id = myHostId ;
  580.     ack.targetId = id ;
  581.     ack.status = status ;
  582.     ack.data = data ;
  583.     sendToNetwork( &ack, sizeof( ack ) ) ;
  584. }
  585.  
  586.  
  587.  
  588. /*------------------------------------------------------------------------------
  589.  * Broadcast a name packet.
  590.  *----------------------------------------------------------------------------*/
  591. static void
  592. broadcastNamePacket(
  593.     long    nPlayer
  594.     )
  595. {
  596.     outNamePacket    name ;
  597.  
  598.     name.type = SERVER_P_NAME ;
  599.     name.id = myHostId ;
  600.     name.nPlayer = nPlayer ;
  601.     strncpy( name.name, cars[nPlayer].name, sizeof( name.name ) ) ;
  602.     sendToNetwork( &name, sizeof( name ) ) ;
  603. }
  604.  
  605.  
  606.  
  607. /*------------------------------------------------------------------------------
  608.  * Broadcast a message packet.
  609.  *----------------------------------------------------------------------------*/
  610. void
  611. broadcastMsgPacket(
  612.     long    nPlayer,
  613.     char    *msg
  614.     )
  615. {
  616.     outMsgPacket    packet ;
  617.  
  618.     packet.type = SERVER_P_MESSAGE ;
  619.     packet.id = myHostId ;
  620.     packet.nPlayer = nPlayer ;
  621.     strncpy( packet.msg, msg, sizeof( packet.msg ) ) ;
  622.     packet.msg[sizeof( packet.msg ) - 1] = '\0' ;
  623.     sendToNetwork( &packet, sizeof( packet ) ) ;
  624.     postNewMessage( nPlayer, msg ) ;
  625. }
  626.  
  627.  
  628.  
  629. /*------------------------------------------------------------------------------
  630.  * Broadcast a course packet.
  631.  *----------------------------------------------------------------------------*/
  632. static void
  633. broadcastCoursePacket(
  634.     outCoursePacket    *packet
  635.     )
  636. {
  637.     sendToNetwork( packet, sizeof( outCoursePacket ) ) ;
  638. }
  639.  
  640.  
  641.  
  642. /*------------------------------------------------------------------------------
  643.  * Broadcast a status packet.
  644.  *----------------------------------------------------------------------------*/
  645. static void
  646. broadcastStatusPacket(
  647.     void
  648.     )
  649. {
  650.     sendToNetwork( &statusPacket, sizeof( outStatusPacket ) ) ;
  651.     lastUpdateTime = currentTime ;
  652. }
  653.  
  654.  
  655.  
  656. /*------------------------------------------------------------------------------
  657.  * Broadcast the race packet.
  658.  *----------------------------------------------------------------------------*/
  659. static void
  660. broadcastRacePacket(
  661.     void
  662.     )
  663. {
  664.     int    i ;
  665.  
  666.     for( i = 0 ; i < MAX_PLAYERS ; i++ )
  667.     {
  668.         racePacket.status[i] = cars[i].status ;
  669.         racePacket.x[i] = player[i].x ;
  670.         racePacket.y[i] = player[i].y ;
  671.         racePacket.z[i] = player[i].z ;
  672.         racePacket.thetaDeg[i] = player[i].thetaDeg ;
  673.         racePacket.roll[i] = player[i].roll ;
  674.         racePacket.headingDeg[i] = player[i].headingDeg ;
  675.         racePacket.totalDis[i] = cars[i].totalDis ;
  676.         racePacket.position[i] = player[i].place ;
  677.         racePacket.desiredSpeed[i] = cars[i].desiredSpeed ;
  678.         racePacket.lane[i] = cars[i].lane ;
  679.         teamPosition[player[i].place - 1] = i ;
  680.     }
  681.     sendToNetwork( &racePacket, sizeof( outRacePacket ) ) ;
  682.     lastRaceTime = currentTime ;
  683.     /*
  684.      * Clear bump bit (bump bit is used to signal collision sound on
  685.      * clients -- need only do once per bump).
  686.      */
  687.     for( i = 0 ; i < MAX_PLAYERS ; i++ )
  688.     {
  689.         cars[i].status &= ~CAR_BUMP ;
  690.     }
  691. }
  692.  
  693.  
  694.  
  695. /*------------------------------------------------------------------------------
  696.  * Write a packet to the network.
  697.  *----------------------------------------------------------------------------*/
  698. static void
  699. sendToNetwork(
  700.     void    *buf,
  701.     int    size
  702.     )
  703. {
  704.     int noCharsSent ;
  705.  
  706.     noCharsSent = sendto( outFd, buf, size, 0, &outAddr, sizeof(outAddr) ) ;
  707.     if( noCharsSent < size )
  708.     {
  709.         fatalError( "multicast sendto: %s", strerror( errno ) ) ;
  710.     }
  711. }
  712.  
  713.  
  714.  
  715. /*------------------------------------------------------------------------------
  716.  * The server main loop.
  717.  *----------------------------------------------------------------------------*/
  718. void
  719. serverRun(
  720.     void
  721.     )
  722. {
  723.     serverFunc() ;
  724.  
  725.     /*
  726.      * Check to send an update packet.
  727.      */
  728.     if( currentTime - lastUpdateTime >= UPDATE_SPACING )
  729.     {
  730.         broadcastStatusPacket() ;
  731.     }
  732.  
  733.     /*
  734.      * Check to broadcast course info.
  735.      */
  736.     if( broadcastCourse != NULL )
  737.     {
  738.         broadcastCoursePacket( broadcastCourse->packet ) ;
  739.         broadcastCourse = broadcastCourse->next ;
  740.     }
  741.  
  742.     /*
  743.      * Read input from clients.
  744.      */
  745.     readInputSocket() ;
  746. }
  747.  
  748.  
  749.  
  750. /*------------------------------------------------------------------------------
  751.  * Read in and store the race courses.
  752.  *----------------------------------------------------------------------------*/
  753. static void
  754. readCourses(
  755.     void
  756.     )
  757. {
  758.     int        n = 0 ;
  759.     CourseNode    *course ;
  760.  
  761.     nCourses = readServerCourses( &courseList ) ;
  762.  
  763.     if( nCourses == 0 )
  764.     {
  765.         fatalError( "No race courses were found!" ) ;
  766.     }
  767.  
  768.     courseVotes = myMalloc( nCourses * sizeof( int ) ) ;
  769.  
  770.     course = courseList ;
  771.     while( course )
  772.     {
  773.         course->packet->type = SERVER_P_COURSE ;
  774.         course->packet->id = myHostId ;
  775.         course->packet->courseId = n ;
  776.         n++ ;
  777.         course = course->next ;
  778.     }
  779. }
  780.  
  781.  
  782.  
  783. /*------------------------------------------------------------------------------
  784.  * Locate a client in the client node list by id.
  785.  *----------------------------------------------------------------------------*/
  786. static ClientNode *
  787. findClient(
  788.     long    id
  789.     )
  790. {
  791.     ClientNode    *client = clientList ;
  792.  
  793.     while( client != NULL && client->id != id )
  794.     {
  795.         client = client->next ;
  796.     }
  797.  
  798.     return( client ) ;
  799. }
  800.  
  801.  
  802.  
  803. /*------------------------------------------------------------------------------
  804.  * Add a player.
  805.  *----------------------------------------------------------------------------*/
  806. static void
  807. addPlayer(
  808.     long    id
  809.     )
  810. {
  811.     int        i ;
  812.     int        n ;
  813.     ClientNode    *client ;
  814.     char        msg[VROOM_MSGLEN] ;
  815.  
  816.     if( ( client = findClient( id ) ) == NULL ||
  817.         client->status != ACK_ST_CANDIDATE )
  818.     {
  819.         printf( "%s tried to become player unsuccessfully\n",
  820.             hostNameFromId( id, 0 ) ) ;
  821.         return ;
  822.     }
  823.  
  824.     client->status = ACK_ST_PLAYER ;
  825.  
  826.     nPlayers++ ;
  827.     statusPacket.nPlayers = nPlayers ;
  828.  
  829.     /*
  830.      * Add player in first computer spot.
  831.      */
  832.     n = -1 ;
  833.     for( i = 0 ; i < MAX_PLAYERS ; i++ )
  834.     {
  835.         if( isRobot[i] == 1 )
  836.         {
  837.             n = i ;
  838.             break ;
  839.         }
  840.     }
  841.  
  842.     if( n == -1 )
  843.     {
  844.         fatalError( "Unforeseen error adding player." ) ;
  845.     }
  846.  
  847.     statusPacket.playerId[n] = id ;
  848.     statusPacket.selection[n] = -1 ;
  849.     isRobot[n] = 0 ;
  850.     broadcastCourse = courseList ;
  851.     client->nextDeadLine = currentTime + CLIENT_TIMEOUT ;
  852. }
  853.  
  854.  
  855.  
  856. /*------------------------------------------------------------------------------
  857.  * Remove a player.
  858.  *----------------------------------------------------------------------------*/
  859. static void
  860. removePlayer(
  861.     long    id
  862.     )
  863. {
  864.     int        i ;
  865.     int        n ;
  866.     char        str[VROOM_MSGLEN] ;
  867.     ClientNode    *client ;
  868.  
  869.     if( ( n = findPlayer( id ) ) == -1 )
  870.     {
  871.         return ;
  872.     }
  873.  
  874.     if( ( client = findClient( id ) ) == NULL ||
  875.         client->status != ACK_ST_PLAYER )
  876.     {
  877.         return ;
  878.     }
  879.  
  880.     nPlayers-- ;
  881.     updateServerCourseLabel( nPlayers ) ;
  882.     statusPacket.nPlayers = nPlayers ;
  883.     statusPacket.playerId[n] = n ;
  884.     isRobot[n] = 1 ;
  885.     sprintf( str, "%s left the game.", cars[n].name ) ;
  886.     broadcastMsgPacket( -1, str ) ;
  887.     strncpy( cars[n].name, robotName[n], sizeof( cars[n].name ) ) ;
  888.     updateNames() ;
  889.     broadcastStatusPacket() ;
  890.     switch( statusPacket.status )
  891.     {
  892.         case SERVER_ST_COURSE_SEL :
  893.             tallyCourseVotes() ;
  894.             break ;
  895.  
  896.         case SERVER_ST_COURSE_ACK :
  897.         case SERVER_ST_PRE_TRIAL :
  898.         case SERVER_ST_TRIAL :
  899.         case SERVER_ST_POST_TRIAL :
  900.         case SERVER_ST_PRE_RACE :
  901.         case SERVER_ST_RACE :
  902.         case SERVER_ST_POST_RACE :
  903.             setMessage( "Repaced %s with robot.\n",
  904.                     hostNameFromId( id, 0 ) ) ;
  905.             break ;
  906.     }
  907.     sfxPlay( alertSfx ) ;
  908. }
  909.  
  910.  
  911.  
  912. /*------------------------------------------------------------------------------
  913.  * Determine a port number from a service name.
  914.  *----------------------------------------------------------------------------*/
  915. int
  916. getPort(
  917.     char    *servName,
  918.     int    defaultPort
  919.     )
  920. {
  921.     int        port ;
  922.     struct servent    *serv ;
  923.  
  924.     /*
  925.      * Get port number for listening to clients.
  926.      */
  927.     if( ( serv = getservbyname( servName, NULL ) ) == NULL )
  928.     {
  929.         port = defaultPort ;
  930.     }
  931.     else
  932.     {
  933.         port = serv->s_port ;
  934.     }
  935.  
  936.     return( port ) ;
  937. }
  938.  
  939.  
  940.  
  941. /*------------------------------------------------------------------------------
  942.  * Process a speed packet.
  943.  *----------------------------------------------------------------------------*/
  944. static int
  945. processSpeedPacket(
  946.     inSpeedPacket    *packet,
  947.     int        size
  948.     )
  949. {
  950.     int    n ;
  951.  
  952.     if( size != sizeof( inSpeedPacket ) )
  953.     {
  954.         return( -1 ) ;
  955.     }
  956.  
  957.     n = packet->playerNumber ;
  958.     if( packet->id == statusPacket.playerId[n] )
  959.     {
  960.         cars[n].desiredSpeed = packet->speed ;
  961.         if( packet->steer != 0 )
  962.         {
  963.             cars[n].status &= ~CHANGE_LANES ;
  964.             cars[n].status |= ( packet->steer & CHANGE_LANES ) ;
  965.         }
  966.     }
  967.  
  968.     return( 0 ) ;
  969. }
  970.  
  971.  
  972.  
  973. /*------------------------------------------------------------------------------
  974.  * Process an info packet.
  975.  *----------------------------------------------------------------------------*/
  976. static int
  977. processInfoPacket(
  978.     inInfoPacket    *packet,
  979.     int        size
  980.     )
  981. {
  982.     if( size != sizeof( inInfoPacket ) )
  983.     {
  984.         return( -1 ) ;
  985.     }
  986.  
  987.     switch( packet->option )
  988.     {
  989.         case CLIENT_INFO_JOIN :
  990.             addClient( packet->id ) ;
  991.             break ;
  992.  
  993.         case CLIENT_INFO_ACCEPT :
  994.             addPlayer( packet->id ) ;
  995.             updateServerCourseLabel( nPlayers ) ;
  996.             sfxPlay( alertSfx ) ;
  997.             break ;
  998.  
  999.         case CLIENT_INFO_QUIT :
  1000.             removePlayer( packet->id ) ;
  1001.             removeClient( packet->id ) ;
  1002.             break ;
  1003.  
  1004.         case CLIENT_INFO_UPDATE :
  1005.             break ;
  1006.  
  1007.         case CLIENT_INFO_COURSE_SEL :
  1008.             clientChoseCourse( packet->id, packet->choice ) ;
  1009.             break ;
  1010.  
  1011.         case CLIENT_INFO_COURSE_ACK :
  1012.             clientAckCourse( packet->id ) ;
  1013.             break ;
  1014.  
  1015.         default :
  1016.             printf( "%s: unknown option (0x%08x) in info packet\n",
  1017.                 basename, packet->option ) ;
  1018.             return( 0 ) ;
  1019.             break ;
  1020.     }
  1021.     resetClientDeadline( packet->id ) ;
  1022.  
  1023.     return( 0 ) ;
  1024. }
  1025.  
  1026.  
  1027.  
  1028. /*------------------------------------------------------------------------------
  1029.  * Process a name packet from a client.
  1030.  *----------------------------------------------------------------------------*/
  1031. static int
  1032. processNamePacket(
  1033.     inNamePacket    *packet,
  1034.     int        size
  1035.     )
  1036. {
  1037.     int    n ;
  1038.  
  1039.     if( size != sizeof( inNamePacket ) )
  1040.     {
  1041.         return( -1 ) ;
  1042.     }
  1043.  
  1044.     if( ( n = findPlayer( packet->id ) ) != -1 )
  1045.     {
  1046.         strncpy( cars[n].name, packet->name, sizeof( cars[n].name ) ) ;
  1047.         updateNames() ;
  1048.     }
  1049.  
  1050.     resetClientDeadline( packet->id ) ;
  1051.  
  1052.     return( 0 ) ;
  1053. }
  1054.  
  1055.  
  1056.  
  1057. /*------------------------------------------------------------------------------
  1058.  * Process a message packet from a client.
  1059.  *----------------------------------------------------------------------------*/
  1060. static int
  1061. processMsgPacket(
  1062.     inMsgPacket    *packet,
  1063.     int        size
  1064.     )
  1065. {
  1066.     int    n ;
  1067.  
  1068.     if( size != sizeof( inMsgPacket ) )
  1069.     {
  1070.         return( -1 ) ;
  1071.     }
  1072.  
  1073.     if( ( n = findPlayer( packet->id ) ) != -1 )
  1074.     {
  1075.         broadcastMsgPacket( n, packet->msg ) ;
  1076.     }
  1077.  
  1078.     resetClientDeadline( packet->id ) ;
  1079.  
  1080.     return( 0 ) ;
  1081. }
  1082.  
  1083.  
  1084.  
  1085. /*------------------------------------------------------------------------------
  1086.  * Add local courses to the selection list.
  1087.  *----------------------------------------------------------------------------*/
  1088. static void
  1089. fillCourseSelectorList(
  1090.     Widget    courseSelector
  1091.     )
  1092. {
  1093.     CourseNode    *course = courseList ;
  1094.  
  1095.     XmListDeleteAllItems( courseSelector ) ;
  1096.     while( course )
  1097.     {
  1098.         addCourseToSelectionList( courseSelector,
  1099.                     course->packet->name ) ;
  1100.         course = course->next ;
  1101.     }
  1102. }
  1103.  
  1104.  
  1105.  
  1106. /*------------------------------------------------------------------------------
  1107.  * Client-called routine to build the course list.
  1108.  *----------------------------------------------------------------------------*/
  1109. int
  1110. addToCourseList(
  1111.     outCoursePacket    *packet
  1112.     )
  1113. {
  1114.     CourseNode    *course ;
  1115.     CourseNode    *newCourse ;
  1116.  
  1117.     /*
  1118.      * First check to see if course is already in list.
  1119.      */
  1120.     course = courseList ;
  1121.     while( course )
  1122.     {
  1123.         if( course->packet->courseId == packet->courseId )
  1124.         {
  1125.             return( 0 ) ;
  1126.         }
  1127.         course = course->next ;
  1128.     }
  1129.  
  1130.     newCourse = myMalloc( sizeof( CourseNode ) ) ;
  1131.     newCourse->packet = myMalloc( sizeof( outCoursePacket ) ) ;
  1132.     newCourse->next = NULL ;
  1133.     bcopy( packet, newCourse->packet, sizeof( outCoursePacket ) ) ;
  1134.  
  1135.     if( courseList == NULL )
  1136.     {
  1137.         courseList = newCourse ;
  1138.     }
  1139.     else
  1140.     {
  1141.         course = courseList ;
  1142.  
  1143.         while( course->next != NULL )
  1144.         {
  1145.             course = course->next ;
  1146.         }
  1147.  
  1148.         course->next = newCourse ;
  1149.     }
  1150.  
  1151.     nCourses++ ;
  1152.  
  1153.     return( 1 ) ;
  1154. }
  1155.  
  1156.  
  1157.  
  1158. /*------------------------------------------------------------------------------
  1159.  * Clear the course list (free up memory).
  1160.  *----------------------------------------------------------------------------*/
  1161. void
  1162. clearCourseList(
  1163.     void
  1164.     )
  1165. {
  1166.     CourseNode    *course = courseList ;
  1167.     CourseNode    *next ;
  1168.  
  1169.     while( course )
  1170.     {
  1171.         next = course->next ;
  1172.         free( course->packet ) ;
  1173.         free( course ) ;
  1174.         course = next ;
  1175.     }
  1176.  
  1177.     courseList = NULL ;
  1178.     nCourses = 0 ;
  1179. }
  1180.  
  1181.  
  1182.  
  1183. /*------------------------------------------------------------------------------
  1184.  * Return the matching course in the list.
  1185.  *----------------------------------------------------------------------------*/
  1186. outCoursePacket    *
  1187. findCourseInList(
  1188.     char    *name
  1189.     )
  1190. {
  1191.     CourseNode    *course = courseList ;
  1192.  
  1193.     while( course )
  1194.     {
  1195.         if( !strcmp( name, course->packet->name ) )
  1196.         {
  1197.             return( course->packet ) ;
  1198.         }
  1199.         course = course->next ;
  1200.     }
  1201.  
  1202.     return( NULL ) ;
  1203. }
  1204.  
  1205.  
  1206.  
  1207. /*------------------------------------------------------------------------------
  1208.  * Return the matching course in the list based on course id.
  1209.  *----------------------------------------------------------------------------*/
  1210. outCoursePacket    *
  1211. findCourseInListById(
  1212.     long    courseId
  1213.     )
  1214. {
  1215.     CourseNode    *course = courseList ;
  1216.  
  1217.     while( course )
  1218.     {
  1219.         if( course->packet->courseId == courseId )
  1220.         {
  1221.             return( course->packet ) ;
  1222.         }
  1223.         course = course->next ;
  1224.     }
  1225.  
  1226.     return( NULL ) ;
  1227. }
  1228.  
  1229.  
  1230.  
  1231. /*------------------------------------------------------------------------------
  1232.  * Update the client list, checking for timeouts.
  1233.  *----------------------------------------------------------------------------*/
  1234. static void
  1235. updateClientList(
  1236.     void
  1237.     )
  1238. {
  1239.     ClientNode    *client ;
  1240.     ClientNode    *prev ;
  1241.  
  1242.     if( clientList == NULL )
  1243.     {
  1244.         return ;
  1245.     }
  1246.  
  1247.     prev = NULL ;
  1248.     client = clientList ;
  1249.  
  1250.     while( client )
  1251.     {
  1252.         if( client->id != myHostId &&
  1253.             client->nextDeadLine < currentTime )
  1254.         {
  1255.             printf( "client %s didn't respond by deadline\n",
  1256.                 hostNameFromId( client->id, 0 ) ) ;
  1257.             removePlayer( client->id ) ;
  1258.             removeClient( client->id ) ;
  1259.         }
  1260.         prev = client ;
  1261.         client = prev->next ;
  1262.     }
  1263. }
  1264.  
  1265.  
  1266.  
  1267. /*------------------------------------------------------------------------------
  1268.  * Return the index of a player given the id.
  1269.  *----------------------------------------------------------------------------*/
  1270. static int
  1271. findPlayer(
  1272.     long    id
  1273.     )
  1274. {
  1275.     int    i ;
  1276.  
  1277.     for( i = 0 ; i < MAX_PLAYERS ; i++ )
  1278.     {
  1279.         if( statusPacket.playerId[i] == id )
  1280.         {
  1281.             return( i ) ;
  1282.         }
  1283.     }
  1284.  
  1285.     return( -1 ) ;
  1286. }
  1287.  
  1288.  
  1289.  
  1290. /*------------------------------------------------------------------------------
  1291.  * Handle a client choosing a course.
  1292.  *----------------------------------------------------------------------------*/
  1293. void
  1294. clientChoseCourse(
  1295.     long    id,
  1296.     int    choice
  1297.     )
  1298. {
  1299.     int        i ;
  1300.     int        n ;
  1301.     char        msg[MAX_COURSE_NAME+12] ;
  1302.     CourseNode    *cn = courseList ;
  1303.  
  1304.     if( choice < 0 || choice >= nCourses )
  1305.     {
  1306.         broadcastAckPacket( id, ACK_ST_COURSE_VOTE, -1 ) ;
  1307.         return ;
  1308.     }
  1309.     else
  1310.     {
  1311.         broadcastAckPacket( id, ACK_ST_COURSE_VOTE, choice ) ;
  1312.     }
  1313.  
  1314.     if( ( n = findPlayer( id ) ) != -1 )
  1315.     {
  1316.         for( i = 0 ; i < choice ; i++ )
  1317.         {
  1318.             cn = cn->next ;
  1319.         }
  1320.         sprintf( msg, "I chose %s.", cn->packet->name ) ;
  1321.         broadcastMsgPacket( n, msg ) ;
  1322.         statusPacket.selection[n] = choice ;
  1323.         tallyCourseVotes() ;
  1324.     }
  1325.  
  1326.     if( id == myHostId )
  1327.     {
  1328.         busyCursor() ;
  1329.         setAdminForm( courseVoteForm ) ;
  1330.         unbusyCursor() ;
  1331.     }
  1332. }
  1333.  
  1334.  
  1335.  
  1336. /*------------------------------------------------------------------------------
  1337.  * Handle a client acknowledging a course selection.
  1338.  *----------------------------------------------------------------------------*/
  1339. void
  1340. clientAckCourse(
  1341.     long    id
  1342.     )
  1343. {
  1344.     int    n ;
  1345.  
  1346.     if( ( n = findPlayer( id ) ) != -1 )
  1347.     {
  1348.         statusPacket.selection[n] = 1 ;
  1349.     }
  1350. }
  1351.  
  1352.  
  1353.  
  1354. /*------------------------------------------------------------------------------
  1355.  * Check if all players have voted for a course.  If so, choose majority
  1356.  * winner or pick randomly if a tie among top vote getters.
  1357.  *----------------------------------------------------------------------------*/
  1358. static void
  1359. tallyCourseVotes(
  1360.     void
  1361.     )
  1362. {
  1363.     int    i ;
  1364.     int    n ;
  1365.     int    topVotes = 0 ;
  1366.     int    topCourse = -1 ;
  1367.  
  1368.     for( i = 0 ; i < nCourses ; i++ )
  1369.     {
  1370.         courseVotes[i] = 0 ;
  1371.     }
  1372.  
  1373.     for( i = 0 ; i < MAX_PLAYERS ; i++ )
  1374.     {
  1375.         if( isRobot[i] == 0 )
  1376.         {
  1377.             if( statusPacket.selection[i] != -1 )
  1378.             {
  1379.                 n = ++(courseVotes[statusPacket.selection[i]]) ;
  1380.                 if( n > topVotes )
  1381.                 {
  1382.                     topVotes = n ;
  1383.                 }
  1384.             }
  1385.             else
  1386.             {
  1387.                 return ;
  1388.             }
  1389.         }
  1390.     }
  1391.  
  1392.     n = 0 ;
  1393.     for( i = 0 ; i < nCourses ; i++ )
  1394.     {
  1395.         if( courseVotes[i] == topVotes )
  1396.         {
  1397.             n++ ;
  1398.         }
  1399.     }
  1400.  
  1401.     topCourse = (int)( n * (float)( rand() % 0x0ff ) / (float)( 0x100 ) ) ;
  1402.  
  1403.     /*
  1404.      * Safety check.
  1405.      */
  1406.     if( topCourse >= n )
  1407.     {
  1408.         topCourse = n - 1 ;
  1409.     }
  1410.  
  1411.     /*
  1412.      * Pick the course.
  1413.      */
  1414.     for( i = 0 ; i < nCourses ; i++ )
  1415.     {
  1416.         if( courseVotes[i] == topVotes )
  1417.         {
  1418.             n-- ;
  1419.             if( n == topCourse )
  1420.             {
  1421.                 startTeamTrials( i ) ;
  1422.                 return ;
  1423.             }
  1424.         }
  1425.     }
  1426. }
  1427.  
  1428.  
  1429.  
  1430. /*------------------------------------------------------------------------------
  1431.  * Initialize for starting time trials in team mode.  Send status and wait for
  1432.  * all players to respond.
  1433.  *----------------------------------------------------------------------------*/
  1434. static void
  1435. startTeamTrials(
  1436.     int    courseNumber
  1437.     )
  1438. {
  1439.     int        i ;
  1440.     CourseNode    *cn = courseList ;
  1441.  
  1442.     for( i = 0 ; i < courseNumber ; i++ )
  1443.     {
  1444.         cn = cn->next ;
  1445.     }
  1446.  
  1447.     broadcastCoursePacket( cn->packet ) ;
  1448.     broadcastAckPacket( VROOM_ALL_PLAYERS, ACK_ST_COURSE_CHOSEN,
  1449.                 courseNumber ) ;
  1450.     for( i = 0 ; i < MAX_PLAYERS ; i++ )
  1451.     {
  1452.         statusPacket.selection[i] = 0 ;
  1453.     }
  1454.     statusPacket.selection[0] = 1 ;
  1455.     serverFunc = serverWaitForCourseAck ;
  1456.     serverDeadLine = currentTime + COURSE_ACK_DEADLINE ;
  1457.     statusPacket.status = SERVER_ST_COURSE_ACK ;
  1458.     broadcastStatusPacket() ;
  1459.  
  1460.     raceCoursePacket = cn->packet ;
  1461. }
  1462.  
  1463.  
  1464.  
  1465. /*------------------------------------------------------------------------------
  1466.  * Do nothing while waiting for course selections.
  1467.  *----------------------------------------------------------------------------*/
  1468. static void
  1469. serverWaitForCourseSel(
  1470.     void
  1471.     )
  1472. {
  1473. }
  1474.  
  1475.  
  1476.  
  1477. /*------------------------------------------------------------------------------
  1478.  * Continue sending selected course info until all players acknowledge.
  1479.  *----------------------------------------------------------------------------*/
  1480. static void
  1481. serverWaitForCourseAck(
  1482.     void
  1483.     )
  1484. {
  1485.     int        i ;
  1486.     int        n = -1 ;
  1487.     static float    ackLastTime = 0.0f ;
  1488.  
  1489.     if( currentTime - ackLastTime > UPDATE_SPACING )
  1490.     {
  1491.         ackLastTime = currentTime ;
  1492.         broadcastAckPacket( VROOM_ALL_PLAYERS, ACK_ST_COURSE_CHOSEN,
  1493.                     raceCoursePacket->courseId ) ;
  1494.     }
  1495.  
  1496.     for( i = 0 ; i < MAX_PLAYERS ; i++ )
  1497.     {
  1498.         if( isRobot[i] == 0 && statusPacket.selection[i] == 0 )
  1499.         {
  1500.             n = i ;
  1501.         }
  1502.     }
  1503.  
  1504.     /*
  1505.      * All have acknowledged.  Start the time trials.
  1506.      */
  1507.     if( n == -1 )
  1508.     {
  1509.         if( loadTrackFromPacket( raceCoursePacket ) != 0 )
  1510.         {
  1511.             fatalError( "Unexpected error creating chosen race"
  1512.                     " course.  Aborting execution." ) ;
  1513.         }
  1514.         serverFunc = serverPreTrial ;
  1515.         nCars = 1 ;
  1516.         initSoloCars( 1 ) ;
  1517.         setRobotChars( TRIAL_SKILL_LEVEL ) ;
  1518.         startTime = currentTime + 10.0f ;
  1519.         startSoundTime = startTime - 2.0f ;
  1520.         racePacket.type = SERVER_P_RACE ;
  1521.         racePacket.id = myHostId ;
  1522.         racePacket.mode = SERVER_ST_PRE_TRIAL ;
  1523.         statusPacket.status = SERVER_ST_PRE_TRIAL ;
  1524.         broadcastStatusPacket() ;
  1525.         racePacket.time = 5.0f ;
  1526.         startTimeTrials( 0 ) ;
  1527.         for( i = 0 ; i < MAX_PLAYERS ; i++ )
  1528.         {
  1529.             racePacket.indTime[i] = 0.0f ;
  1530.         }
  1531.     }
  1532.     else
  1533.     {
  1534.         /*
  1535.          * If still here, not all players have acknowledged the course
  1536.          * selection.  Drop 'em.
  1537.          */
  1538.         if( currentTime > serverDeadLine )
  1539.         {
  1540.             printf( "player %d (%s) did not acknowledge the "
  1541.                 "course in time.\n", n,
  1542.                 hostNameFromId( statusPacket.playerId[n], 0 ) );
  1543.             removePlayer( statusPacket.playerId[n] ) ;
  1544.         }
  1545.     }
  1546. }
  1547.  
  1548.  
  1549.  
  1550. /*------------------------------------------------------------------------------
  1551.  * Main loop during pre-trial.
  1552.  *----------------------------------------------------------------------------*/
  1553. static void
  1554. serverPreTrial(
  1555.     void
  1556.     )
  1557. {
  1558.     int    i ;
  1559.  
  1560.     racePacket.time = startTime - currentTime ;
  1561.     sfxPlayPitch( motorSfx, 0.5f * cars[self].desiredSpeed * speedFactor ) ;
  1562.     if( racePacket.time <= 0.0f )
  1563.     {
  1564.         sfxPlay( startSfx ) ;
  1565.         sfxPlayPitch( motorSfx, cars[self].desiredSpeed *
  1566.                 speedFactor ) ;
  1567.         serverFunc = serverTrial ;
  1568.         for( i = 0 ; i < MAX_PLAYERS ; i++ )
  1569.         {
  1570.             cars[i].startLapTime = currentTime ;
  1571.             cars[i].finishTime = 0.0f ;
  1572.             cars[i].totalDis = 0.0f ;
  1573.         }
  1574.         carsFinished = 0 ;
  1575.         startTime = currentTime + racePacket.time ;
  1576.         lastTime = currentTime ;
  1577.         racePacket.time = 0.0f ;
  1578.         setMessage( "Best of %d laps is used to qualify.",
  1579.                 VROOM_TRIAL_LAPS ) ;
  1580.         racePacket.mode = SERVER_ST_TRIAL ;
  1581.         statusPacket.status = SERVER_ST_TRIAL ;
  1582.         broadcastStatusPacket() ;
  1583.     }
  1584.     else if( currentTime > startSoundTime )
  1585.     {
  1586.         sfxPlay( toneSfx ) ;
  1587.         startSoundTime += 1.0f ;
  1588.     }
  1589.  
  1590.     broadcastRacePacket() ;
  1591.  
  1592.     drawIt( self ) ;
  1593.     drawPreTrialOverlay( racePacket.time, teamPosition, 1, 0 ) ;
  1594.     GLwDrawingAreaSwapBuffers( mainOgl ) ;
  1595. }
  1596.  
  1597.  
  1598.  
  1599. /*------------------------------------------------------------------------------
  1600.  * Empty function to hold place.
  1601.  *----------------------------------------------------------------------------*/
  1602. static void
  1603. serverNoOp(
  1604.     void
  1605.     )
  1606. {
  1607. }
  1608.  
  1609.  
  1610.  
  1611. /*------------------------------------------------------------------------------
  1612.  * Run the time trials.
  1613.  *----------------------------------------------------------------------------*/
  1614. static void
  1615. serverTrial(
  1616.     void
  1617.     )
  1618. {
  1619.     int    i ;
  1620.     float    dTime ;
  1621.  
  1622.     dTime = currentTime - lastTime ;
  1623.     lastTime = currentTime ;
  1624.  
  1625.     racePacket.time = currentTime - startTime ;
  1626.  
  1627.     doAllCars( dTime, VROOM_TRIAL_LAPS, 1 ) ;
  1628.     computeDistances( VROOM_TRIAL_LAPS ) ;
  1629.     checkCarFinishes( VROOM_TRIAL_LAPS, racePacket.indTime, 1 ) ;
  1630.     if( cars[self].status & CAR_FINISHED )
  1631.     {
  1632.         serverFunc = serverPostTrial ;
  1633.         racePacket.mode = SERVER_ST_POST_TRIAL ;
  1634.         statusPacket.status = SERVER_ST_POST_TRIAL ;
  1635.         broadcastStatusPacket() ;
  1636.         endRaceTime = currentTime + 3.0f ;
  1637.         setMessage( "Waiting for all players to qualify.\n" ) ;
  1638.         sfxDisable( motorSfx ) ;
  1639.         stopSkid( cars+self ) ;
  1640.     }
  1641.     broadcastRacePacket() ;
  1642.     drawIt( self ) ;
  1643.     drawTrialOverlay( racePacket.indTime[self], teamPosition ) ;
  1644.     GLwDrawingAreaSwapBuffers( mainOgl ) ;
  1645. }
  1646.  
  1647.  
  1648.  
  1649. /*------------------------------------------------------------------------------
  1650.  * After the time trials, wait for all robots to finish at least one lap.
  1651.  *----------------------------------------------------------------------------*/
  1652. static void
  1653. serverPostTrial(
  1654.     void
  1655.     )
  1656. {
  1657.     int    i ;
  1658.     int    l ;
  1659.     float    dTime ;
  1660.     float    skill ;
  1661.     float    avgRobotTime ;
  1662.     float    avgHumanTime ;
  1663.     float    bestRobotTime = 1e30 ;
  1664.     float    nextBestRobotTime = 1e30 ;
  1665.  
  1666.     racePacket.time = currentTime - startTime ;
  1667.  
  1668.     if( carsFinished == MAX_PLAYERS && currentTime > endRaceTime )
  1669.     {
  1670.         placeCarsForStart() ;
  1671.         avgRobotTime = 0.0f ;
  1672.         avgHumanTime = 0.0f ;
  1673.         for( i = 0 ; i < MAX_PLAYERS ; i++ )
  1674.         {
  1675.             cars[i].lap = -1 ;
  1676.             cars[i].totalDis = cars[i].s - 1.0f ;
  1677.             cars[i].lapDis = cars[i].totalDis ;
  1678.             cars[i].status = 0 ;
  1679.             if( isRobot[i] )
  1680.             {
  1681.                 avgRobotTime += cars[i].bestLapTime ;
  1682.                 if( cars[i].bestLapTime < bestRobotTime )
  1683.                 {
  1684.                     nextBestRobotTime = bestRobotTime ;
  1685.                     bestRobotTime = cars[i].bestLapTime ;
  1686.                 }
  1687.                 else if( cars[i].bestLapTime <
  1688.                     nextBestRobotTime )
  1689.                 {
  1690.                     nextBestRobotTime = cars[i].bestLapTime;
  1691.                 }
  1692.             }
  1693.             else
  1694.             {
  1695.                 avgHumanTime += cars[i].bestLapTime ;
  1696.             }
  1697.         }
  1698.         avgHumanTime /= (float)nPlayers ;
  1699.         /*
  1700.          * Try to adjust robot skill factors based on average
  1701.          * qualification times of human players.
  1702.          */
  1703.         if( nPlayers < MAX_PLAYERS )
  1704.         {
  1705.             if( nextBestRobotTime < avgHumanTime )
  1706.             {
  1707.                 skill = ( 1.0f - 0.02f * avgHumanTime /
  1708.                     nextBestRobotTime ) *
  1709.                     TRIAL_SKILL_LEVEL ;
  1710.             }
  1711.             else
  1712.             {
  1713.                 skill = 0.20f * ( 1.0f - TRIAL_SKILL_LEVEL ) *
  1714.                     nextBestRobotTime / avgHumanTime +
  1715.                     TRIAL_SKILL_LEVEL ;
  1716.             }
  1717.             skill = MINFUNC( skill, 1.0f ) ;
  1718.             setRobotChars( skill ) ;
  1719.         }
  1720.         serverFunc = serverPreRace ;
  1721.         sfxEnable( motorSfx ) ;
  1722.         i = teamPosition[0] ;
  1723.         l = 0 ;
  1724.         for( i = 1 ; i < MAX_PLAYERS ; i++ )
  1725.         {
  1726.             if( cars[i].bestLapTime < cars[l].bestLapTime )
  1727.             {
  1728.                 l = i ;
  1729.             }
  1730.         }
  1731.         showRecord = checkLapRecord( cars[l].bestLapTime,
  1732.                         cars[l].name, 1 ) ;
  1733.         racePacket.mode = SERVER_ST_PRE_RACE ;
  1734.         statusPacket.status = SERVER_ST_PRE_RACE ;
  1735.         nCars = MAX_PLAYERS ;
  1736.         startTime = currentTime + 10.0f ;
  1737.         startSoundTime = startTime - 2.0f ;
  1738.         broadcastStatusPacket() ;
  1739.     }
  1740.     else
  1741.     {
  1742.         dTime = currentTime - lastTime ;
  1743.         lastTime = currentTime ;
  1744.         doAllCars( dTime, VROOM_TRIAL_LAPS, 1 ) ;
  1745.         i = computeDistances( VROOM_TRIAL_LAPS ) ;
  1746.         /*
  1747.          * Check if all human players have finished.
  1748.          */
  1749.         l = 0 ;
  1750.         for( i = 0 ; i < MAX_PLAYERS ; i++ )
  1751.         {
  1752.             if( !isRobot[i] &&
  1753.                 ( cars[i].status & CAR_FINISHED ) != 0 )
  1754.             {
  1755.                 l++ ;
  1756.             }
  1757.         }
  1758.         if( l != nPlayers )
  1759.         {
  1760.             endRaceTime += dTime ;
  1761.         }
  1762.         checkCarFinishes( VROOM_TRIAL_LAPS, racePacket.indTime, 1 ) ;
  1763.         /*
  1764.          * Go ahead and end if computer cars have finished at least
  1765.          * one lap.
  1766.          */
  1767.         if( l == nPlayers && currentTime - endRaceTime > 2.0f )
  1768.         {
  1769.             for( i = 0 ; i < MAX_PLAYERS ; i++ )
  1770.             {
  1771.                 if( isRobot[i] && cars[i].lap > 0 &&
  1772.                     ( cars[i].status & CAR_FINISHED ) == 0 )
  1773.                 {
  1774.                     autoFinishCar( i, 0.0f ) ;
  1775.                 }
  1776.             }
  1777.         }
  1778.         drawIt( self ) ;
  1779.         drawPostTrialOverlay( racePacket.indTime[self], teamPosition ) ;
  1780.         GLwDrawingAreaSwapBuffers( mainOgl ) ;
  1781.     }
  1782.     broadcastRacePacket() ;
  1783. }
  1784.  
  1785.  
  1786.  
  1787. /*------------------------------------------------------------------------------
  1788.  * Main loop for before the race.
  1789.  *----------------------------------------------------------------------------*/
  1790. static void
  1791. serverPreRace(
  1792.     void
  1793.     )
  1794. {
  1795.     int    i ;
  1796.     float    dTime ;
  1797.  
  1798.     racePacket.time = startTime - currentTime ;
  1799.     sfxPlayPitch( motorSfx, 0.5f * cars[self].desiredSpeed * speedFactor ) ;
  1800.     if( racePacket.time <= 0.0f )
  1801.     {
  1802.         sfxPlay( startSfx ) ;
  1803.         sfxPlayPitch( motorSfx, cars[self].desiredSpeed *
  1804.                 speedFactor ) ;
  1805.         for( i = 0 ; i < MAX_PLAYERS ; i++ )
  1806.         {
  1807.             cars[i].startLapTime = currentTime ;
  1808.             cars[i].finishTime = 0.0f ;
  1809.             cars[i].totalDis = 0.0f ;
  1810.         }
  1811.         carsFinished = 0 ;
  1812.         startTime = currentTime + racePacket.time ;
  1813.         lastTime = currentTime ;
  1814.         racePacket.time = 0.0f ;
  1815.         setMessage( "May the best driver win." ) ;
  1816.         serverFunc = serverRace ;
  1817.         startLastLap = 0 ;
  1818.         racePacket.mode = SERVER_ST_RACE ;
  1819.         statusPacket.status = SERVER_ST_RACE ;
  1820.         broadcastStatusPacket() ;
  1821.     }
  1822.     else if( currentTime > startSoundTime )
  1823.     {
  1824.         sfxPlay( toneSfx ) ;
  1825.         startSoundTime += 1.0f ;
  1826.     }
  1827.     broadcastRacePacket() ;
  1828.     drawIt( 0 ) ;
  1829.     drawPreTrialOverlay( racePacket.time, teamPosition, 0, showRecord ) ;
  1830.     GLwDrawingAreaSwapBuffers( mainOgl ) ;
  1831. }
  1832.  
  1833.  
  1834.  
  1835. /*------------------------------------------------------------------------------
  1836.  * Main loop for race.
  1837.  *----------------------------------------------------------------------------*/
  1838. static void
  1839. serverRace(
  1840.     void
  1841.     )
  1842. {
  1843.     float    dTime ;
  1844.     int    dLaps ;
  1845.     int    n ;
  1846.  
  1847.     racePacket.time = currentTime - startTime ;
  1848.     dTime = currentTime - lastTime ;
  1849.     lastTime = currentTime ;
  1850.  
  1851.     doAllCars( dTime, raceLaps, 0 ) ;
  1852.     computePositions( teamPosition, raceLaps ) ;
  1853.     checkCarFinishes( raceLaps, racePacket.indTime, 0 ) ;
  1854.     autoFinish() ;
  1855.     loadTimes( raceLaps ) ;
  1856.     if( cars[self].status & CAR_FINISHED )
  1857.     {
  1858.         sfxDisable( motorSfx ) ;
  1859.         stopSkid( cars+self ) ;
  1860.         serverFunc = serverPostRace ;
  1861.         showFinishMessage() ;
  1862.         racePacket.mode = SERVER_ST_POST_RACE ;
  1863.         statusPacket.status = SERVER_ST_POST_RACE ;
  1864.         broadcastStatusPacket() ;
  1865.         endRaceTime = currentTime + 3.0f ;
  1866.     }
  1867.     else if( cars[self].lap == raceLaps - 1 && startLastLap == 0 )
  1868.     {
  1869.         startLastLap = 1 ;
  1870.         sfxPlay( lastlapSfx ) ;
  1871.     }
  1872.     broadcastRacePacket() ;
  1873.     drawIt( 0 ) ;
  1874.     if( player[self].place == 1 )
  1875.     {
  1876.         dLaps = (int)( cars[self].totalDis -
  1877.                 cars[teamPosition[1]].totalDis ) / nTracks ;
  1878.         drawRaceOverlay( racePacket.time, raceLaps - cars[self].lap - 1,
  1879.                 dLaps, 1, teamPosition ) ;
  1880.     }
  1881.     else
  1882.     {
  1883.         n = teamPosition[0] ;
  1884.         if( cars[n].status & CAR_FINISHED )
  1885.         {
  1886.             dLaps = raceLaps - cars[self].lap - 1 ;
  1887.         }
  1888.         else
  1889.         {
  1890.             dLaps = (int)( cars[n].totalDis -
  1891.                     cars[self].totalDis ) / nTracks ;
  1892.         }
  1893.         drawRaceOverlay( racePacket.time, raceLaps - cars[self].lap - 1,
  1894.                 dLaps, 0, teamPosition ) ;
  1895.     }
  1896.     GLwDrawingAreaSwapBuffers( mainOgl ) ;
  1897. }
  1898.  
  1899.  
  1900.  
  1901. /*------------------------------------------------------------------------------
  1902.  * Main loop for after race.
  1903.  *----------------------------------------------------------------------------*/
  1904. static void
  1905. serverPostRace(
  1906.     void
  1907.     )
  1908. {
  1909.     int    i ;
  1910.     int    st ;
  1911.     float    d ;
  1912.     float    dTime ;
  1913.  
  1914.     racePacket.time = currentTime - startTime ;
  1915.     if( carsFinished == MAX_PLAYERS && currentTime > endRaceTime )
  1916.     {
  1917.         serverFunc = serverNoOp ;
  1918.         racePacket.mode = SERVER_ST_RESULTS ;
  1919.         statusPacket.status = SERVER_ST_RESULTS ;
  1920.         broadcastStatusPacket() ;
  1921.         nCars = 1 ;
  1922.         showTeamResults( teamPosition ) ;
  1923.         for( i = 0 ; i < MAX_PLAYERS ; i++ )
  1924.         {
  1925.             statusPacket.selection[i] = -1 ;
  1926.         }
  1927.     }
  1928.     else
  1929.     {
  1930.         autoFinish() ;
  1931.         dTime = currentTime - lastTime ;
  1932.         if( carsFinished != MAX_PLAYERS )
  1933.         {
  1934.             endRaceTime += dTime ;
  1935.         }
  1936.         lastTime = currentTime ;
  1937.         doAllCars( dTime, raceLaps, 0 ) ;
  1938.         computePositions( teamPosition, raceLaps ) ;
  1939.         checkCarFinishes( raceLaps, racePacket.indTime, 0 ) ;
  1940.         loadTimes( raceLaps ) ;
  1941.         broadcastRacePacket() ;
  1942.         drawIt( 0 ) ;
  1943.         drawPostRaceOverlay( racePacket.indTime[self], racePacket.time,
  1944.                     teamPosition ) ;
  1945.         GLwDrawingAreaSwapBuffers( mainOgl ) ;
  1946.     }
  1947. }
  1948.  
  1949.  
  1950.  
  1951. /*------------------------------------------------------------------------------
  1952.  * Compute the lap and total distances during trial runs.
  1953.  *----------------------------------------------------------------------------*/
  1954. static int
  1955. computeDistances(
  1956.     int    laps
  1957.     )
  1958. {
  1959.     int    i ;
  1960.     int    finished = 0 ;
  1961.  
  1962.     for( i = 0 ; i < MAX_PLAYERS ; i++ )
  1963.     {
  1964.         cars[i].lapDis = (float)( ( cars[i].track->number +
  1965.                     nTracks - 1 ) % nTracks ) + cars[i].s ;
  1966.         cars[i].totalDis = cars[i].lapDis + nTracks * cars[i].lap ;
  1967.         if( ( cars[i].status & CAR_FINISHED ) == 0 )
  1968.         {
  1969.             racePacket.indTime[i] = currentTime -
  1970.                         cars[i].startLapTime ;
  1971.         }
  1972.         else
  1973.         {
  1974.             finished++ ;
  1975.         }
  1976.     }
  1977.  
  1978.     return( finished ) ;
  1979. }
  1980.  
  1981.  
  1982.  
  1983. /*------------------------------------------------------------------------------
  1984.  * Compute the times for individual cars during race.
  1985.  *----------------------------------------------------------------------------*/
  1986. static int
  1987. loadTimes(
  1988.     int    laps
  1989.     )
  1990. {
  1991.     int    i ;
  1992.     int    finished = 0 ;
  1993.  
  1994.     for( i = 0 ; i < MAX_PLAYERS ; i++ )
  1995.     {
  1996.         if( ( cars[i].status & CAR_FINISHED ) == 0 )
  1997.         {
  1998.             racePacket.indTime[i] = currentTime - startTime ;
  1999.         }
  2000.         if( isRobot[i] == 0 && cars[i].lap >= laps )
  2001.         {
  2002.             finished++ ;
  2003.         }
  2004.     }
  2005.  
  2006.     return( finished ) ;
  2007. }
  2008.  
  2009.  
  2010.  
  2011. /*------------------------------------------------------------------------------
  2012.  * Exit the server after notifying players.
  2013.  *----------------------------------------------------------------------------*/
  2014. void
  2015. closeServer(
  2016.     void
  2017.     )
  2018. {
  2019.     statusPacket.status = SERVER_ST_QUIT ;
  2020.     broadcastStatusPacket() ;
  2021. }
  2022.  
  2023.  
  2024.  
  2025. /*------------------------------------------------------------------------------
  2026.  * Reset the timeout deadline on a client.
  2027.  *----------------------------------------------------------------------------*/
  2028. static void
  2029. resetClientDeadline(
  2030.     long    id
  2031.     )
  2032. {
  2033.     ClientNode    *client ;
  2034.  
  2035.     if( ( client = findClient( id ) ) != NULL )
  2036.     {
  2037.         client->nextDeadLine = currentTime + CLIENT_TIMEOUT ;
  2038.     }
  2039. }
  2040.  
  2041.  
  2042.  
  2043. /*------------------------------------------------------------------------------
  2044.  * (Re)set server for next game.
  2045.  *----------------------------------------------------------------------------*/
  2046. void
  2047. setServerForNextGame(
  2048.     void
  2049.     )
  2050. {
  2051.     int    i ;
  2052.  
  2053.     serverFunc = serverWaitForCourseSel ;
  2054.     statusPacket.status = SERVER_ST_COURSE_SEL ;
  2055.     broadcastStatusPacket() ;
  2056. }
  2057.  
  2058.  
  2059.  
  2060. /*------------------------------------------------------------------------------
  2061.  * Set the message displayed in the server course selection window.
  2062.  *----------------------------------------------------------------------------*/
  2063. void
  2064. setServerCourseLabel(
  2065.     char    *fmt,
  2066.     ...
  2067.     )
  2068. {
  2069.     va_list        vargs ;
  2070.     int        n ;
  2071.     Arg        arg[1] ;
  2072.     XmString    str ;
  2073.     char        msg[1024] ;
  2074.  
  2075.     va_start( vargs, fmt ) ;
  2076.     if( serverCourseLabel != NULL )
  2077.     {
  2078.         vsprintf( msg, fmt, vargs ) ;
  2079.  
  2080.         str = XmStringCreateLtoR( msg, XmFONTLIST_DEFAULT_TAG ) ;
  2081.         n = 0 ;
  2082.         XtSetArg( arg[n], XmNlabelString, str ) ; n++ ;
  2083.         XtSetValues( serverCourseLabel, arg, n ) ;
  2084.         XmStringFree( str ) ;
  2085.     }
  2086.     va_end( vargs ) ;
  2087. }
  2088.  
  2089.  
  2090.  
  2091. /*------------------------------------------------------------------------------
  2092.  * Update the server course label as players come and go.
  2093.  *----------------------------------------------------------------------------*/
  2094. void
  2095. updateServerCourseLabel(
  2096.     int    np
  2097.     )
  2098. {
  2099.     if( np == 1 )
  2100.     {
  2101.         setServerCourseLabel(
  2102.             "You are the only player.  Selecting a\n"
  2103.             "course now will start the game immediately." ) ;
  2104.     }
  2105.     else
  2106.     {
  2107.         setServerCourseLabel(
  2108.             "There are now %d players.  Vote on a course.\n"
  2109.             "The race will begin when all players have voted\n"
  2110.             "using the course with the most votes.", np ) ;
  2111.     }
  2112. }
  2113.  
  2114.  
  2115.  
  2116. /*------------------------------------------------------------------------------
  2117.  * Broadcast all of the human player names.
  2118.  *----------------------------------------------------------------------------*/
  2119. static void
  2120. updateNames(
  2121.     void
  2122.     )
  2123. {
  2124.     int    i ;
  2125.  
  2126.     for( i = 0 ; i < MAX_PLAYERS ; i++ )
  2127.     {
  2128.         broadcastNamePacket( i ) ;
  2129.     }
  2130. }
  2131.  
  2132.  
  2133.  
  2134. /*------------------------------------------------------------------------------
  2135.  * Check for port number entries in the service listing.
  2136.  *----------------------------------------------------------------------------*/
  2137. void
  2138. checkPorts(
  2139.     void
  2140.     )
  2141. {
  2142.     int        port ;
  2143.     struct servent    *serv ;
  2144.  
  2145.     /*
  2146.      * Get port number for listening to clients.
  2147.      */
  2148.     if( getservbyname( servInputName, NULL ) == NULL ||
  2149.         getservbyname( servOutputName, NULL ) == NULL )
  2150.     {
  2151.         postInfo( NULL, NULL,
  2152.             "Can't find one or more of the following udp services:"
  2153.             "\n\n       `%s'\n       `%s'\n\n"
  2154.             "To run over the network, you must have the following "
  2155.                 "lines\n"
  2156.             "in your /etc/services file.\n\n"
  2157.             "       %s   %d/udp\n"
  2158.             "       %s   %d/udp\n\n"
  2159.             "Defaulting to listed ports.",
  2160.             servInputName, servOutputName,
  2161.             servInputName, VROOM_SERVER_INPUT_PORT,
  2162.             servOutputName, VROOM_CLIENT_INPUT_PORT ) ;
  2163.     }
  2164. }
  2165.  
  2166.  
  2167.  
  2168. /*------------------------------------------------------------------------------
  2169.  * Check to automatically end race if enough humans have finished.
  2170.  *----------------------------------------------------------------------------*/
  2171. static void
  2172. autoFinish(
  2173.     void
  2174.     )
  2175. {
  2176.     int    i ;
  2177.     int    humansDone = 0 ;
  2178.     int    robotsDone = 0 ;
  2179.     int    totalDone ;
  2180.     float    lastFinish = 0.0f ;
  2181.  
  2182.     /*
  2183.      * Go ahead and end if computer cars have finished at least
  2184.      * one lap and all human players have finished.
  2185.      */
  2186.     for( i = 0 ; i < MAX_PLAYERS ; i++ )
  2187.     {
  2188.         if( cars[i].status & CAR_FINISHED )
  2189.         {
  2190.             if( isRobot[i] )
  2191.             {
  2192.                 robotsDone++ ;
  2193.             }
  2194.             else
  2195.             {
  2196.                 humansDone++ ;
  2197.                 if( cars[i].finishTime > lastFinish )
  2198.                 {
  2199.                     lastFinish = cars[i].finishTime ;
  2200.                 }
  2201.             }
  2202.         }
  2203.     }
  2204.     totalDone = robotsDone + humansDone ;
  2205.  
  2206.     /*
  2207.      * If all humans are done, then finish after 7 seconds of last
  2208.      * human finish.
  2209.      */
  2210.     if( humansDone == nPlayers && totalDone < MAX_PLAYERS )
  2211.     {
  2212.         if( currentTime - startTime - lastFinish > 7.0f )
  2213.         {
  2214.             for( i = 0 ; i < MAX_PLAYERS ; i++ )
  2215.             {
  2216.                 if( isRobot[i] && cars[i].lap > 0 &&
  2217.                     ( cars[i].status & CAR_FINISHED ) == 0 )
  2218.                 {
  2219.                     autoFinishCar( i,
  2220.                         currentTime - startTime ) ;
  2221.                     racePacket.indTime[i] =
  2222.                         cars[i].finishTime ;
  2223.                 }
  2224.             }
  2225.         }
  2226.     }
  2227.     /*
  2228.      * If all but one human is done, give him 120 seconds after last
  2229.      * human finish to complete the race.
  2230.      */
  2231.     else if( nPlayers > 1 && totalDone == MAX_PLAYERS - 1 &&
  2232.         currentTime - startTime - lastFinish > 60.0f )
  2233.     {
  2234.         for( i = 0 ; i < MAX_PLAYERS ; i++ )
  2235.         {
  2236.             if( isRobot[i] == 0 && cars[i].lap > 0 &&
  2237.                 ( cars[i].status & CAR_FINISHED ) == 0 )
  2238.             {
  2239.                 autoFinishCar( i, currentTime - startTime ) ;
  2240.                 racePacket.indTime[i] = cars[i].finishTime ;
  2241.             }
  2242.         }
  2243.     }
  2244. }
  2245.